using System;
using System.Collections ; 
using Parseq.Core; 

namespace Parseq.Compiler
{
	/* Exp are intermediate expressions that are being held by Parseq before generating the final parser. 
	 * this is required in order to resolve bindings that are declared (mutally) recursively. 
	 * 
	 */
	public interface IExp {
		object Inner { get ; }
	}
	
	public class CharExp : IExp {
		private char inner;
		public CharExp(char inner) {
			this.inner = inner; 
		}
		
		public object Inner {
			get { return this.inner ; }
		}
        public override string ToString()
        {
            return string.Format("<Char:{0}>", this.inner); 
        }
	}
	
	public class LiteralExp : IExp {
		private readonly string literal; 
		public LiteralExp ( string literal ) {
			this.literal = literal ; 
		}
		
		public object Inner {
			get { return this.literal; }
		}
        public override string ToString()
        {
            return string.Format("<Literal:{0}>", this.literal);
        }
    }

    public class IDExp : IExp
    {
		private readonly string inner;
        public IDExp(string inner)
        {
            this.inner = inner; 
		}
		
		public object Inner {
            get { return this.inner; }
		}
        public override string ToString()
        {
            return string.Format("<ID:{0}>", this.inner);
        }
    }

    public class SkipExp : IExp
    {
		private readonly object inner; 
		public SkipExp(object inner) {
			this.inner = inner; 
		}
		
		public object Inner {
			get { return this.inner; }
		}
	}
	
	public class RepeatExp : IExp {
		private readonly IExp inner ; 
		private readonly long min = 0; 
		private readonly long max = -1; 
		public RepeatExp(IExp inner, long min, long max) {
			this.inner = inner; 
			this.min = min; 
			this.max = max; 
		}
		
		public object Inner {
			get { return this.inner ; }
		}
        public long Min
        {
            get { return this.min; }
        }

        public long Max
        {
            get { return this.max; }
        }

        public override string ToString()
        {
            return string.Format("<Repeat:{0},{1},{2}>", this.inner, this.min, this.max);
        }
    }
	
	public class ChoiceExp : IExp {
		private readonly ArrayList inners ; 
		public ChoiceExp(IExp[] inners) {
			this.inners = new ArrayList(inners); 
		}
		
		public object Inner {
            get { return (IExp[])this.inners.ToArray(typeof(IExp)); }
        }
        public override string ToString()
        {
            return string.Format("<Choice:{0}>", Util.String.ArrayToString(this.inners.ToArray()));
        }
    }
	
	public class SequenceExp : IExp {
		private readonly ArrayList inners ; 
		public SequenceExp (IExp[] inners) {
			this.inners = new ArrayList(inners); 
		}
		
		public object Inner {
			get { return (IExp[])this.inners.ToArray(typeof(IExp)); }
		}
        public override string ToString()
        {
            return string.Format("<Sequence:{0}>", Util.String.ArrayToString(this.inners.ToArray()));
        }
    }

    public class TokenExp : IExp
    {
        private readonly string id;
        private readonly IExp def;
        public TokenExp(IDExp id, IExp def)
        {
            this.id = (string)id.Inner;
            this.def = def; 
        }

        public object Inner
        {
            get { return this.def; }
        }

        public string ID
        {
            get { return this.id; }
        }
        public override string ToString()
        {
            return string.Format("<TokenDef:{0} : {1}>", this.id, this.def);
        }
    }

    public interface IExpFactory {
        BaseParser BuildParser(IExp exp); 
    }

	// so what does each rule by us? 
	// 1 - we need to ensure that every single rule has an entry. (i.e. we are allowed to define rules without entries but we'll
	// need to "re-bind" them after a while... 
	// that means we need to have some sort of "global" object that can be used to handle the re-binding" after the first 
	// pass!!!. 
	
	// 1 - parse through the tokens and keep track of the token names. 
	// 2 - resolve the tokens by going through each expression to see if they exists in the symbol table (if they do not exist - that's an error)
	// 3 - separate the parsers into lexer & the parser step. 
	// 4 - compile the final class..!!!. 
}

